local skynet = require "skynet"
require "skynet.manager"
local ServiceName = require "enum.ServiceName"
local Timer = require "core.Timer"

local osdate = os.date
local stringfmt = string.format

local M = {}

-- 日志录入频率，单位秒，默认60s写入一次日志
local loggerInterval = skynet.getenvn("logger_interval") or 6
-- 一个channel的日志条数，超过该数量，则进行一次数据录入
local logger_count = skynet.getenvn("logger_count") or 100
local loggerRemain = 0

-- 不是daemon模式，日志需要打印到控制台
local nodaemon = skynet.getenv("daemon") == nil
local logPath = skynet.getenv("logpath")

-- 等待录入的日志
---@type table<string, Logger>
local loggers = {}
local function flush()
    for _, logger in pairs(loggers) do
        local file = io.open(logger.path, "a")
        if not file then
            skynet.error("can't open logger file: " .. logger.path)
            return
        end

        file:write(table.concat(logger.logs, "\n"))
        logger.logs = {}
        file:flush()
        file:close()
    end

    loggerRemain = 0
    loggers = {}
end

local function newlogger(channel)
    local date = osdate("%Y-%m-%d")
    ---@class Logger
    ---@field logs table<number, string>
    local logger = {
        date = date,
        path = stringfmt("%s/%s-%s.log", logPath, channel, date),
        logs = {}
    }

    loggers[channel] = logger
    return loggers[channel]
end

local function log(logType, channel, ...)
    local date = osdate("%Y-%m-%d")
    local time = osdate("%H:%M:%S")

    local logger = loggers[channel]
    if not logger then
        logger = newlogger(channel)
    elseif logger.date ~= date then
        flush() -- 进行一次数据录入
        logger = newlogger(channel)
    end

    local content = stringfmt("[%s %s] - %s\n\t%s\n", date, time, logType, table.concat({...}, " "))

    table.insert(logger.logs, content)
    loggerRemain = loggerRemain + 1
    if loggerRemain >= logger_count then
        -- 日志数量过多，进行一次数据录入
        flush()
    end

    if nodaemon then
        print(stringfmt("%s %s\n", channel, content))
    end
end

function M.init()
    skynet.dispatch("lua", function(_, _, logType, channel, ...)
        if logType == "flush" then
            flush()
            return
        end

        log(logType, channel, ...)
    end)

    Timer.intervalSec(flush, loggerInterval, loggerInterval)
    skynet.register(ServiceName.GAME_LOGGER)
end

return M
